package com.atguigu.userprofile.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.userprofile.bean.TagCondition;
import com.atguigu.userprofile.bean.TagInfo;
import com.atguigu.userprofile.bean.UserGroup;
import com.atguigu.userprofile.constants.ConstCodes;
import com.atguigu.userprofile.mapper.UserGroupMapper;
import com.atguigu.userprofile.service.TagInfoService;
import com.atguigu.userprofile.service.UserGroupService;
import com.atguigu.userprofile.utils.RedisUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangchen
 * @since 2021-05-04
 */
@Service
@Slf4j
@DS("mysql")
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {

    @Autowired
    TagInfoService tagInfoService;

    @Override
    public void saveUserGroupInfo(UserGroup userGroup) {
        //补充3个字段  条件json  条件的中文描述  创建日期
        String conditionJSON = JSON.toJSONString(userGroup.getTagConditions());
        userGroup.setConditionJsonStr(conditionJSON);
        userGroup.setConditionComment(userGroup.conditionJsonToComment());
        userGroup.setCreateTime(new Date());
        saveOrUpdate(userGroup);



    }

    @Override
    public void genUserGroup(UserGroup userGroup) {
        insertSQL( userGroup);


    }
   //把人群包写入redis中 user_group_id ,   us (uids )
    public void genUserGroupRD(UserGroup userGroup){
        // type ?   set    key ?   user_group:101    value ?  uid     field/score?  无  写入api ?  sadd   读取api? sismembers 判存   过期时间？不设过期时间
        Jedis jedis = RedisUtil.getJedis();
        //  查询clickhouse 得到人群包
        List<String> uidList= baseMapper.getUidListFromUserGroup(userGroup.getId().toString());
        // 再把人群包写入redis
        String key ="user_group:"+userGroup.getId().toString();
        jedis.sadd(key,uidList.toArray(new String[]{}));
        jedis.close();
    }

    public void insertSQL(UserGroup userGroup){
        String tableName="user_group";
        String bitmapAndSQL = bitmapAndSQL(userGroup);
        String insertSQL="insert into "+tableName+" select '"+userGroup.getId()+"', "+bitmapAndSQL;
        System.out.println(insertSQL);
        this.baseMapper.insertUserGroupCK(insertSQL);


    }

    private  String bitmapAndSQL(UserGroup userGroup){
        List<TagCondition> tagConditions = userGroup.getTagConditions();

        // 查询整个标签表  提取为一个map 方便查询
        Map<String ,TagInfo> tagMap = tagInfoService.getTagInfoMapWithCode();

        StringBuilder  bitmapQuerySQLBuilder = new StringBuilder();

        for (TagCondition tagCondition : tagConditions) {
            String subQuerySQL  =getSubQuery(tagCondition,tagMap,userGroup.getBusiDate());
            if(bitmapQuerySQLBuilder.length()==0){
                bitmapQuerySQLBuilder.append(subQuerySQL);
            }else {
                bitmapQuerySQLBuilder.insert(0,"bitmapAnd(").append(",").append(subQuerySQL).append(")");
            }

            System.out.println(subQuerySQL);
        }
        System.out.println(bitmapQuerySQLBuilder.toString());
        return bitmapQuerySQLBuilder.toString();
    }


// SELECT groupBitmapMergeState(us)
//        FROM user_tag_value_string
//        WHERE (tag_code = 'TG_PERSON_BASE_AGEGROUP') AND (tag_value IN ('90后', '80后')) AND (dt = '2021-05-16')
//  1  表   --> 标签值类型   根据标签编码 查询标签的定义
//	    2   标签编码 --> tag_code
//        3   标签值   -->  运算符号   用英文转义为 符号
//                     -->  要不单引   标签值类型
//                     -->  要不要多个值拼接 	 看值的个数
//                   -->  要不要加括号
//        4   日期     -->   业务日期 busiDate
    private  String getSubQuery(TagCondition tagCondition,Map<String ,TagInfo> tagMap,String busiDate ){
        String tagCode = tagCondition.getTagCode();
        TagInfo tagInfo = tagMap.get(tagCode);
        String tagValueType = tagInfo.getTagValueType();
        String tableName ="";
        if(ConstCodes.TAG_VALUE_TYPE_STRING.equals(tagValueType)){
            tableName="user_tag_value_string";
        }else if(ConstCodes.TAG_VALUE_TYPE_LONG.equals(tagValueType)){
            tableName="user_tag_value_long";
        }else if(ConstCodes.TAG_VALUE_TYPE_DATE.equals(tagValueType)){
            tableName="user_tag_value_date";
        }else if(ConstCodes.TAG_VALUE_TYPE_DECIMAL.equals(tagValueType)){
            tableName="user_tag_value_decimal";
        }
        String sqlOperator = getConditionOperator(tagCondition.getOperator());

        List<String> tagValues = tagCondition.getTagValues();
        String tagValueSQL=null;
        if (ConstCodes.TAG_VALUE_TYPE_DATE .equals(tagValueType)||ConstCodes.TAG_VALUE_TYPE_STRING .equals(tagValueType)){
              tagValueSQL = "'" + StringUtils.join(tagCondition.getTagValues(), "','") + "'";
        }else{
              tagValueSQL =  StringUtils.join(tagCondition.getTagValues(), ",") ;
        }

        if("in".equals(tagCondition.getOperator())||"nin".equals(tagCondition.getOperator())){
            tagValueSQL="("+tagValueSQL+")";
        }
        String  subQuerySQL="( SELECT groupBitmapMergeState(us) " +
                "        FROM  "+tableName+
                "       WHERE (tag_code = '"+tagCode+"') AND (tag_value " +sqlOperator+ " " +tagValueSQL+"  ) AND (dt = '"+busiDate+"') )";
        return  subQuerySQL;

    }

    // 把中文的操作代码转换为 判断符号
    private  String getConditionOperator(String operator){
        switch (operator){
            case "eq":
                return "=";
            case "lte":
                return "<=";
            case "gte":
                return ">=";
            case "lt":
                return "<";
            case "gt":
                return ">";
            case "neq":
                return "<>";
            case "in":
                return "in";
            case "nin":
                return "not in";
        }
        throw  new RuntimeException("操作符不正确");
    }

}
